DEFINITION MODULE  Strings;

(*****************************************************************************)
(* Das Modul stellt Prozeduren zur Verarbeitung von 'Strings' zur Verfue-    *)
(* gung. Strings bestehen aus einem eindimensionalen Feld von Einzelzeichen: *)
(*                                                                           *)
(*   z.B. String10 = ARRAY [0..9] OF CHAR;                                   *)
(*                                                                           *)
(* Das Modul definiert auch einige Standard-Stringtypen.                     *)
(* Die Laenge eines Strings ist allerdings nicht durch die statische Defi-   *)
(* nition im Programmtext festgelegt, sondern wird dynamisch zur Laufzeit    *)
(* bestimmt ( Length( string ) ).                                            *)
(*                                                                           *)
(* Als Endekennung gilt folgende ( allgemein uebliche ) Konvention:          *)
(*                                                                           *)
(*   1. Das Ende eines Strings wird durch ein Nullbyte ( = TermChar ) hinter *)
(*      dem letzten Buchstaben gekennzeichnet, falls der Platz dazu in dem   *)
(*      Feld ausreicht.                                                      *)
(*                                                                           *)
(*   2. Das Ende des Strings ist durch den maximalen Index des Feldes        *)
(*      ( ermittelt durch HIGH( string ) ) gegeben, falls der String so viele*)
(*      Buchstaben wie das Feld Zeichen hat, dann ist naemlich kein Platz    *)
(*      fuer das Nullbyte.                                                   *)
(*                                                                           *)
(* Der Compiler selber benutzt auch diese Endekennung: Bei der Zuweisung     *)
(* eines konstanten Textes an eine Stringvariable wird ein Nullbyte ange-    *)
(* fuegt, falls noch Platz ist. Ruft man eine Prozedur mit einem konstanten  *)
(* Text als Parameter auf, wird ein Feld uebergeben, das genausoviele Zeichen*)
(* hat wie der String - ein Nullbyte wird nicht angefuegt.                   *)
(*                                                                           *)
(* Obwohl bei der Definition eines Strings womoeglich der Index bei Null be- *)
(* ginnt, beginnt die Zaehlung der Buchstaben bei den Prozeduren, die eine   *)
(* Positionsangabe benoetigen, bei eins ! D.h. der erste Buchstabe des       *)
(* Strings hat die Position eins.                                            *)
(*                                                                           *)
(* Die Prozeduren sind so ausgelegt, dass die Operationen scheinbar mit Hilfe*)
(* >endlos< langer Strings ausgefuehrt werden, und was nachher nicht in den  *)
(* Ergebnisstring passt, wird einfach abgeschnitten. Ueber die Variable      *)
(* 'vollst' kann man dann erfahren, ob der Zielstring das vollstaendige      *)
(* Ergebnis enthaelt.                                                        *)
(*                                                                           *)
(* Da viele Programme nur die grundlegenden Stringfunktionen benoetigen -    *)
(* wenn ueberhaupt -, sind diese hier zusammengefasst. Neben den gegenueber  *)
(* dem Wirth'schen Standardmodul leicht erweiterten Funktionen, sind noch    *)
(* Funktionen fuer die Verwendung von Einzelzeichen in Strings vorgesehen;   *)
(* konstante Einzelzeichen, also z.B. 'b', koennen auch direkt mit den       *)
(* Stringprozeduren verarbeitet werden, da sie kompatibel mit Strings der    *)
(* Laenge eins sind.                                                         *)
(*                                                                           *)
(* Hinweis: Die Angabe von Null als Wert fuer Prozeduren, die eine Positions-*)
(* angabe benoetigen, erzeugt meistens sinnvolle Ersatzwerte; z.B erspart    *)
(* man sich die Berechnung der Stringlaenge, bei Prozeduren, die vom Ende    *)
(* des Strings aus suchen.                                                   *)
(*___________________________________________________________________________*)
(*  07-Feb-90 , Holger Kleinschmidt                                          *)
(*****************************************************************************)



  TYPE  CompareResult = ( less, equal, greater );


        StrChar = ARRAY [0..  0] OF CHAR; (* z.B fuer die platzsparende   *)
                                          (* Umwandlung einer CHAR-Varia- *)
                                          (* blen in einen String.        *)
        Str20   = ARRAY [0.. 19] OF CHAR;
        Str80   = ARRAY [0.. 79] OF CHAR;
        Str256  = ARRAY [0..255] OF CHAR;

(*___________________________________________________________________________*)


  PROCEDURE  Length ((* EIN/ -- *)  string : ARRAY OF CHAR ): CARDINAL;

(*---------------------------------------------------------------------------
 | Ermittelt die Laenge eines Strings zur Laufzeit. Wenn der String leer ist |
 | ( IsEmptyStr ), bekommt man eine Null.                                    |
  ---------------------------------------------------------------------------*)


  PROCEDURE  ClearStr   ((* -- /AUS *) VAR string: ARRAY OF CHAR );

  PROCEDURE  IsEmptyStr ((* EIN/ -- *)     string: ARRAY OF CHAR ):BOOLEAN;

(*---------------------------------------------------------------------------
 | Erzeugt einen Leerstring, bzw. testet, ob ein String leer ist             |
  ---------------------------------------------------------------------------*)



  PROCEDURE  Assign ((* EIN/ -- *)     quelle : ARRAY OF CHAR;
                     (* -- /AUS *) VAR ziel   : ARRAY OF CHAR;
                     (* -- /AUS *) VAR vollst : BOOLEAN       );

(*---------------------------------------------------------------------------
 | Zuweisung von Strings. Falls <ziel> den String <quelle> nicht vollstaen-  |
 | dig aufnehmen kann, wird nur bis zum Ende von <ziel> kopiert und es gilt: |
 |  <vollst> = FALSE.                                                        |
  ---------------------------------------------------------------------------*)


  PROCEDURE  Concat ((* EIN/ -- *)     quelle1,
                     (* EIN/ -- *)     quelle2 : ARRAY OF CHAR;
                     (* -- /AUS *) VAR ziel    : ARRAY OF CHAR;
                     (* -- /AUS *) VAR vollst  : BOOLEAN       );

(*---------------------------------------------------------------------------
 | Zusammenfuegen von Strings. <quelle2> wird an <quelle1> hinten dran ge-   |
 | haengt und das ganze nach <ziel> kopiert, allerdings nur soviel wie <ziel>|
 | aufnehmen kann. Konnte <ziel> nicht alles aufnehmen, gilt:                |
 |   <vollst> = FALSE.                                                       |
  ---------------------------------------------------------------------------*)


  PROCEDURE  Delete ((* EIN/AUS *) VAR string : ARRAY OF CHAR;
                     (* EIN/ -- *)     start,
                     (* EIN/ -- *)     laenge : CARDINAL      );

(*---------------------------------------------------------------------------
 | Ab dem <start>-ten Zeichen werden <laenge> Zeichen aus <string> entfernt. |
 |  - <start> = 0 bedeutet das gleiche wie <start> = 1; es wird also beim    |
 |    ersten Zeichen begonnen.                                               |
 |  - Liegt <start> ausserhalb des Strings, passiert gar nichts.             |
 |  - Liegt <start> + <laenge> ausserhalb des Strings, wird nur bis zum Ende |
 |    von <string> geloescht.                                                |
  ---------------------------------------------------------------------------*)



  PROCEDURE  Insert ((* EIN/ -- *)     insert : ARRAY OF CHAR;
                     (* EIN/ -- *)     start  : CARDINAL;
                     (* EIN/AUS *) VAR string : ARRAY OF CHAR;
                     (* -- /AUS *) VAR vollst : BOOLEAN       );

(*---------------------------------------------------------------------------
 | Ab dem <start>-ten Zeichen wird <insert> in <string> eingefuegt.          |
 |  - <start> = 0  <=>  <start> = 1                                          |
 |  - Liegt <start> ausserhalb von <string>, wird <insert> hinten angefuegt  |
 |     ( => 'Concat' )                                                       |
 |  - Ist <insert> ein Leerstring, passiert gar nichts                       |
 |  - Falls das Ergebnis nicht mehr in <quelle1> passt, wird der hintere Rest|
 |    abgeschnitten und es gilt   <vollst> = FALSE                           |
  ---------------------------------------------------------------------------*)


  PROCEDURE  EqualStr    ((* EIN/ -- *) string1,
                          (* EIN/ -- *) string2 : ARRAY OF CHAR ): BOOLEAN;

  PROCEDURE  EqualCAPStr ((* EIN/ -- *) string1,
                          (* EIN/ -- *) string2 : ARRAY OF CHAR ): BOOLEAN;

(*---------------------------------------------------------------------------
 | Vergleichen <string1> und <string2> zeichenweise miteinander; fuer den    |
 | Vergleich ist die Endemarkierung der Strings ohne Bedeutung,d.h. wenn z.B.|
 | <string1> durch ein Nullbyte abgeschlossen ist, <string2> aber durch das  |
 | Ende des Feldes, und beide Strings sind sonst gleich, so liefert auch     |
 | diese Funktion TRUE.                                                      |
 | "EqualCAPStr" unterscheidet nicht zwischen Gross- und Kleinschreibung.    |
 | Diese Prozeduren sind als schneller Ersatz fuer "Compare" bei der Komman- |
 | doanalyse o.ae. gedacht.                                                  |
  ---------------------------------------------------------------------------*)



  PROCEDURE  Compare ((* EIN/ -- *) string1,
                      (* EIN/ -- *) string2 : ARRAY OF CHAR ): CompareResult;

(*---------------------------------------------------------------------------
 | Vergleicht <string1> und <string2> zeichenweise miteinander.              |
 | Das Ergebnis wird folgendermassen gebildet ( lexikographische Ordnung ):  |
 |                                                                           |
 |  - Beim ersten Zeichen von <string1>, dass kleiner ( groesser ) als das   |
 |    entsprechende Zeichen bei <string2> ist, wird 'less' ('greater') zu-   |
 |    rueckgeliefert.                                                        |
 |  - Sind beide Strings gleichlang ( Endekennung spielt keine Rolle !! ),   |
 |    und stimmen die Zeichen bis zum Ende ueberein, wird 'equal' zurueckge- |
 |    liefert.                                                               |
 |  - Ist <string1> kuerzer (laenger) als <string2> und stimmen bis zur      |
 |    Laenge von <string1> ( <string2> ) alle Zeichen ueberein, wird 'less'  |
 |    ('greater') zurueckgeliefert.                                          |
 |                                                                           |
 | "Compare" vergleicht wirklich nur den ASCII-Wert der einzelnen Zeichen;   |
 | dabei ist also z.B. 'A' groesser als 'z' !                                |
  ---------------------------------------------------------------------------*)



  PROCEDURE  LeftPos  ((* EIN/ -- *) muster : ARRAY OF CHAR;
                       (* EIN/ -- *) start  : CARDINAL;
                       (* EIN/ -- *) string : ARRAY OF CHAR;
                       (* EIN/ -- *) links  : BOOLEAN       ): CARDINAL;

  PROCEDURE  RightPos ((* EIN/ -- *) muster : ARRAY OF CHAR;
                       (* EIN/ -- *) start  : CARDINAL;
                       (* EIN/ -- *) string : ARRAY OF CHAR;
                       (* EIN/ -- *) links  : BOOLEAN       ): CARDINAL;

(*---------------------------------------------------------------------------
 | Die Prozeduren suchen ab dem <start>-ten Zeichen ( vom Stringanfang ge-   |
 | zaehlt ) zum Ende (Anfang) von                                            |
 | <string> hin nach dem ersten Auftreten von <muster> in <string>.          |
 | Zurueckgegeben wird die Position des ersten Zeichens von <muster> in      |
 | <string> oder Null, falls <muster> nicht oder nicht vollstaendig in       |
 | <string> auftritt.                                                        |
 |                                                                           |
 |  - Mit <links> laesst sich bestimmen, ob die Position des Musters vom     |
 |    Anfang oder vom Ende von <string> gerechnet wird. Beispiel:            |
 |      <string> = 'abcdefg', <muster> = 'bc',                               |
 |    Falls <links> = TRUE, liefert LeftPos 2, sonst 6.                      |
 |    Dadurch lassen sich auf einfache Weise "LeftStr" und "RightStr" benut- |
 |    zen.                                                                   |
 |  - <start> = 0: Bei "LeftPos"  <=> <start> = 1,                           |
 |    bei "RightPos" <=> <start> = Length( quelle ) - Length( muster ) + 1,  |
 |    d.h. es wird soweit rechts wie moeglich mit der Suche begonnen.        |
 |  - Liegt <start> ausserhalb von <string>, oder ist <muster> ein Leer-     |
 |    string, wird Null zurueckgegeben. Bei "RightPos" wird ein ausserhalb   |
 |    des Strings liegendes <start> wie <start> = 0 behandelt.               |
  ---------------------------------------------------------------------------*)



  PROCEDURE  LeftStr  ((* EIN/ -- *)     quelle : ARRAY OF CHAR;
                       (* EIN/ -- *)     anzahl : CARDINAL;
                       (* -- /AUS *) VAR ziel   : ARRAY OF CHAR;
                       (* -- /AUS *) VAR vollst : BOOLEAN       );

  PROCEDURE  RightStr ((* EIN/ -- *)     quelle : ARRAY OF CHAR;
                       (* EIN/ -- *)     anzahl : CARDINAL;
                       (* -- /AUS *) VAR ziel   : ARRAY OF CHAR;
                       (* -- /AUS *) VAR vollst : BOOLEAN       );

(*---------------------------------------------------------------------------
 | Die Prozeduren kopieren die ersten (letzten) <anzahl> Zeichen von <quelle>|
 | nach <ziel>.                                                              |
 |  - Ist <anzahl> groesser als die Laenge von <quelle>, werden nur soviele  |
 |    Zeichen kopiert wie <quelle> enthaelt.                                 |
 |  - Ist <anzahl> gleich Null, wird <ziel> zum Leerstring.                  |
 |  - Es werden nur soviele Zeichen kopiert, wie in <ziel> passen, musste    |
 |    gekuerzt werden, gilt:   <vollst> = FALSE.                             |
 |  - Als <anzahl> laesst sich gut das Ergebnis von "Left/RightPos" benutzen |
  ---------------------------------------------------------------------------*)



  PROCEDURE  SubStr ((* EIN/ -- *)     quelle : ARRAY OF CHAR;
                     (* EIN/ -- *)     start,
                     (* EIN/ -- *)     laenge : CARDINAL;
                     (* -- /AUS *) VAR ziel   : ARRAY OF CHAR;
                     (* -- /AUS *) VAR vollst : BOOLEAN       );

(*---------------------------------------------------------------------------
 | Kopiert ab dem <start>-ten Zeichen <laenge> Zeichen von <quelle> nach     |
 | <ziel>.                                                                   |
 |  - <start> = 0  <=>  <start> = 1.                                         |
 |  - Liegt <start> ausserhalb von <quelle>, oder ist <laenge> gleich Null,  |
 |    wird <ziel> zum Leerstring.                                            |
 |  - Liegt <start> + <laenge> ausserhalb von <quelle>, wird nur bis zum Ende|
 |    von <quelle> kopiert.                                                  |
 |  - Es werden nur soviele Zeichen kopiert, wie in <ziel> passen, musste    |
 |    gekuerzt werden, gilt:   <vollst> = FALSE.                             |
  ---------------------------------------------------------------------------*)


  PROCEDURE  CAPStr ((* EIN/ -- *)     quelle : ARRAY OF CHAR;
                     (* -- /AUS *) VAR ziel   : ARRAY OF CHAR;
                     (* -- /AUS *) VAR vollst : BOOLEAN       );

(*---------------------------------------------------------------------------
 | Alle Kleinbuchstaben aus <quelle> werden in Grossbuchstaben umgewandelt   |
 | und das Ergebnis <ziel> zugewiesen.                                       |
 |  - Es werden nur soviele Zeichen kopiert, wie in <ziel> passen; musste    |
 |    gekuerzt werden, gilt:   <vollst> = FALSE.                             |
  ---------------------------------------------------------------------------*)




  PROCEDURE  CharToStr ((* EIN/ -- *)     zeichen : CHAR;
                        (* -- /AUS *) VAR string  : ARRAY OF CHAR );

(*---------------------------------------------------------------------------
 | <string> wird zu einem String mit der Laenge eins und dem Zeichen         |
 | <zeichen>. Die Prozedur ist gedacht fuer Funktionen, die nur mit Strings  |
 | und nicht mit CHAR-Variablen arbeiten. Als platzsparender Stringtyp kann  |
 | dafuer "StrChar" verwendet werden.                                        |
  ---------------------------------------------------------------------------*)


  PROCEDURE  AssignChar ((* EIN/ -- *)     zeichen: CHAR;
                         (* EIN/ -- *)     pos    : CARDINAL;
                         (* EIN/AUS *) VAR string : ARRAY OF CHAR );

(*---------------------------------------------------------------------------
 | Das <pos>-te Zeichen von <string> wird durch <zeichen> ersetzt. Liegt     |
 | <pos> ausserhalb des Strings, wird <string> nicht veraendert.             |
 |                                                                           |
 |  - Ist <zeichen> ein Nullbyte, hat der <string> danach die Laenge <pos>-1 |
  ---------------------------------------------------------------------------*)


  PROCEDURE  AppendChar ((* EIN/ -- *)     zeichen: CHAR;
                         (* EIN/AUS *) VAR string : ARRAY OF CHAR;
                         (* -- /AUS *) VAR vollst : BOOLEAN       );

(*---------------------------------------------------------------------------
 | <zeichen> wird an das Ende von <string> geschrieben. Der String wird da-  |
 | durch um ein Zeichen laenger, Ist der String nicht gross genug, das zu-   |
 | saetzliche Zeichen aufzunehmen, wird <string> nicht veraendert, und es    |
 | gilt:      <vollst> = FALSE                                               |
 |                                                                           |
 |  - Ist <zeichen> ein Nullbyte, wird <string> nicht veraendert, und es gilt|
 |    vollst = TRUE                                                          |
  ---------------------------------------------------------------------------*)


  PROCEDURE  GetChar ((* EIN/ -- *) string : ARRAY OF CHAR;
                      (* EIN/ -- *) pos    : CARDINAL      ): CHAR;

(*---------------------------------------------------------------------------
 | Liefert das <pos>-te Zeichen von <string>. Liegt <pos> ausserhalb von     |
 | <string> (0, > Length( string )), wird ein Nullbyte zurueckgeliefert.     |
  ---------------------------------------------------------------------------*)


  PROCEDURE  DeleteChar ((* EIN/AUS *) VAR string : ARRAY OF CHAR;
                         (* EIN/ -- *)     pos    : CARDINAL      );

(*---------------------------------------------------------------------------
 | Das <pos>-te Zeichen von <string> wird geloescht, der String wird dadurch |
 | um ein Zeichen kuerzer. Liegt <pos> ausserhalb des Strings, wird das      |
 | LETZTE Zeichen geloescht ( z.B. um ein "AppendChar" rueckgaengig zu       |
 | machen. Ist <string> ein Leerstring, passiert nichts.                     |
  ---------------------------------------------------------------------------*)


  PROCEDURE  InsertChar ((* EIN/ -- *)     zeichen: CHAR;
                         (* EIN/ -- *)     pos    : CARDINAL;
                         (* EIN/AUS *) VAR string : ARRAY OF CHAR;
                         (* -- /AUS *) VAR vollst : BOOLEAN       );

(*---------------------------------------------------------------------------
 | An der Stelle <pos> wird <zeichen> in <string> eingefuegt, der String wird|
 | dadurch um ein Zeichen laenger. Ist <string> nicht gross genug, das zu-   |
 | saetzliche Zeichen aufzunehmen, geht das letzte Zeichen verloren, und es  |
 | gilt:   <vollst> = FALSE.                                                 |
 | Liegt <pos> ausserhalb des Strings, wird <zeichen> hinten angefuegt.      |
 |                                                                           |
 |  - Ist <zeichen> ein Nullbyte, wird <string> nicht veraendert, und es gilt|
 |    vollst = TRUE                                                          |
  ---------------------------------------------------------------------------*)

END  Strings.
